/**
 * 通用uni-app网络请求
 * 基于 Promise 对象实现更简单的 request 使用方式，支持请求和响应拦截
 */

export default {
	config: {
		// #ifdef H5
		baseUrl: "/dev-api",			// H5公众号
		// #endif
		// #ifndef H5
		baseUrl: 'http://localhost:8080',   // 小程序，直接用路径
		// #endif
		header: {
			'Content-Type':'application/json;charset=UTF-8',
			'Content-Type':'application/x-www-form-urlencoded'
		},
		data: {},
		method: "GET",
		dataType: "json",  /* 如设为json，会对返回的数据做一次 JSON.parse */
		responseType: "text",
		success() {},
		fail() {},
		complete() {}
	},
	interceptor: {
		request: (config, needToken, userStore) => {
			// 发起请求前，显示加载器，不需要则关闭
			// uni.showLoading({
			//     title: '加载中'
			// });

			// 获取store中用户信息
			if(needToken) {
				if(userStore){
					// 登录流程控制中，根据本地是否存在token判断用户的登录情况
					// 但是即使token存在，也有可能token是过期的，所以在每次的请求头中携带token
					// 后台根据携带的token判断用户的登录情况，并返回给我们对应的状态码
					// 而后我们可以在响应拦截器中，根据状态码进行一些统一的操作。
					const token = userStore.token;
					const tokenName = userStore.tokenName ? userStore.tokenName : 'Authorization';
					// token && (config.header['Authorization'] = token);
					// 为空也赋值，防止token为空了，不重新赋值，会用缓存的token
					config.header[tokenName] = token
				}else {
					console.error("userStore未配置，无法添加token！！！");
				}
			}
			if(config.type == 'form'){
				config.header['Content-Type'] = 'application/x-www-form-urlencoded';
			}else if(config.type == 'json'){
				config.header['Content-Type'] = 'application/json;charset=UTF-8';
			}

			// 记录版本和渠道
			// #ifdef APP-PLUS
			config.header['PlatformType'] = 'APP'
			config.header['PlatformVersion'] = plus.runtime.versionCode
			// #endif
			// #ifdef MP-WEIXIN
			config.header['PlatformType'] = 'WEIXIN'
			// #endif
			// #ifdef MP-ALIPAY
			config.header['PlatformType'] = 'ALIPAY'
			// #endif
			// #ifdef MP-TOUTIAO
			config.header['PlatformType'] = 'TOUTIAO'
			// #endif
			// #ifdef H5
			config.header['PlatformType'] = 'H5'
			// #endif
		},
		response: (response) => {
			// 请求返回后，关闭加载
			// uni.hideLoading();
			//判断返回状态 执行相应操作
			return response;
		}
	},
	/**
	 * 重新封装uni.request()，其实就是按需配置_config
	 * @param {Object} options
	 * @param {Boolean} needToken 是否需要token，传给interceptor.request
	 */
	request(options, needToken, userStore) {
		if (!options) {
			options = {}
		}
		options.baseUrl = options.baseUrl || this.config.baseUrl
		options.dataType = options.dataType || this.config.dataType
		options.url = options.baseUrl + options.url
		options.data = options.data || {}
		options.method = options.method || this.config.method
		//TODO 加密数据

		//TODO 数据签名
		/*
		_token = {'token': getStorage(STOREKEY_LOGIN).token || 'undefined'},
		_sign = {'sign': sign(JSON.stringify(options.data))}
		options.header = Object.assign({}, options.header, _token,_sign)
		*/

		return new Promise((resolve, reject) => {
			let _config = null

			// uni.request调用结束的回调函数（调用成功、失败都会执行）这里对结果response拦截处理
			options.complete = (response) => {
				let statusCode = response.statusCode
				response.config = _config
				if (process.env.NODE_ENV === 'development') {
					if (statusCode === 200) {
						// console.log("【" + _config.requestId + "】 结果：" + JSON.stringify(response.data))
						console.log("【" + _config.requestId + "】"+ _config.method +" 请求："+response.config.url+"，结果：" + response.data.msg)
					}
				}
				if (this.interceptor.response) {
					let newResponse = this.interceptor.response(response)
					if (newResponse) {
						response = newResponse
					}
				}
				// 统一的响应日志记录
				// _reslog(response)

				// 这部分当然也可以放到拦截器interceptor.response中去做，不过拦截器中可以被覆盖，统一的还是放这了
				if (statusCode === 200) { //成功
					if (response.data.code === 200) {
						resolve(response.data);  					// 后面要用到的就只有data
					}else if (response.data.code === 401) {  		// token 无效
						// 请求退出
						this.logout(userStore)
						// 个人中心不跳转
						if(uni.$xl.router.currentPage() !== '/pages/user/index') uni.$xl.router.push("user")
						// reject(response.data.msg);
						reject("请登录操作");
					}else if (response.data.code === 402) {    	// token 过期
						// 获取store中用户信息
						console.log("token过期")
						if(userStore){
							const refresh_token = userStore.refresh_token;
							// refresh_token不为空则刷新token
							if(refresh_token && refresh_token !== ''){
								console.log("刷新token")
								// 请求刷新token
								uni.request({
									url:  _config.baseUrl + "/auth/refreshToken", //仅为示例，并非真实接口地址。
									method: 'POST',
									header: {
										'Content-Type':'application/x-www-form-urlencoded;charset=utf-8',
										'Authorization': refresh_token
									},
									success: (res) => {
										if(res.data.code === 401){
											// refresh_token也过期了
											console.log("refresh_token也过期了")
											// 请求退出
											this.logout(userStore)
											// 个人中心不跳转
											if(uni.$xl.router.currentPage() !== '/pages/user/index') uni.$xl.router.push("login")
											reject("用户token已过期");
										}else{
											// 重置token和user
											if(userStore.setToken){
												userStore.setToken(res.data.token);
											}else{
												console.error("userStore未配置setToken方法，无法刷新token设置新token！！！");
											}
											// 刷新token没有经过认证成功处理，不会调用获取用户信息接口，所以没有user信息
											// store.commit('SET_USER', res.data.user);
											// 修改新的token
											_config.header['Authorization'] = res.data.token;
											// console.log(_config);
											// 刷新token后，重新请求
											// 用原先的请求config，只是修改了token再次访问下，实现用户无感的刷新token再次请求数据
											uni.request(_config);
										}
									},
									fail: (err) => {
										console.log(err);
										// 请求退出
										this.logout(userStore)
										// 个人中心不跳转
										if(uni.$xl.router.currentPage() !== '/pages/user/index') uni.$xl.router.push("login")
										reject(err);
									},
								});
							}else{
								// 请求退出
								this.logout(userStore)
								// 个人中心不跳转
								if(uni.$xl.router.currentPage() !== '/pages/user/index') uni.$xl.router.push("login")
								reject(response.data.msg);
							}
						}else{
							console.error("userStore未配置，无法刷新token！！！");
							// 个人中心不跳转
							if(uni.$xl.router.currentPage() !== '/pages/user/index') uni.$xl.router.push("login")
							reject(response.data.msg);
						}

					}else{											// 其他的业务错误
						reject(response.data.msg);
					}
				} else {
					switch (response.statusCode) {
						case 400: response.errMsg = '请求错误(400)' ; break;
						case 401: response.errMsg = '未授权，请重新登录(401)'; break;
						case 403: response.errMsg = '拒绝访问(403)'; break;
						case 404: response.errMsg = '请求出错(404)'; break;
						case 408: response.errMsg = '请求超时(408)'; break;
						case 500: response.errMsg = '服务器错误(500)'; break;
						case 501: response.errMsg = '服务未实现(501)'; break;
						case 502: response.errMsg = '网络错误(502)'; break;
						case 503: response.errMsg = '服务不可用(503)'; break;
						case 504: response.errMsg = '网络超时(504)'; break;
						case 505: response.errMsg = 'HTTP版本不受支持(505)'; break;
						default: response.errMsg = `连接出错(${response.statusCode})!`;
					}
					reject(response.errMsg)
				}
			}


			// 传参options覆盖默认配置config，之后赋值为_config
			_config = Object.assign({}, this.config, options)
			_config.requestId = new Date().getTime()

			// 请求时判断拦截器是否为空，不为空则拦截修改_config配置
			if (this.interceptor.request) {
				this.interceptor.request(_config, needToken, userStore)
			}

			// 统一的请求日志记录
			// _reqlog(_config)

			if (process.env.NODE_ENV === 'development') {
				console.log("【" + _config.requestId + "】 地址：" + _config.url)
				if (_config.data) {
					console.log("【" + _config.requestId + "】 参数：" + JSON.stringify(_config.data))
				}
			}

			// 将最后的_config传给uni.request进行请求
			uni.request(_config);
		});
	},
	// 请求服务器退出操作
	logout(userStore){
		if(userStore && userStore.logout){
			userStore.logout();
		}else if(userStore){
			console.error("userStore未配置logout方法，无法调用logout请求服务器退出操作！！！");
		}else{
			console.error("userStore未配置，无法请求服务器退出操作！！！");
		}
	},
	get(url, data, options) {
		if (!options) {
			options = {}
		}
		options.url = url
		options.data = data
		options.method = 'GET'
		return this.request(options)
	},
	post(url, data, options) {
		if (!options) {
			options = {}
		}
		options.url = url
		options.data = data
		options.method = 'POST'
		return this.request(options)
	},
	put(url, data, options) {
		if (!options) {
			options = {}
		}
		options.url = url
		options.data = data
		options.method = 'PUT'
		return this.request(options)
	},
	delete(url, data, options) {
		if (!options) {
			options = {}
		}
		options.url = url
		options.data = data
		options.method = 'DELETE'
		return this.request(options)
	}
}


/**
 * 请求接口日志记录
 */
function _reqlog(req) {
	if (process.env.NODE_ENV === 'development') {
		console.log("【" + req.requestId + "】 地址：" + req.url)
		if (req.data) {
			console.log("【" + req.requestId + "】 请求参数：" + JSON.stringify(req.data))
		}
	}
	//TODO 调接口异步写入日志数据库
}

/**
 * 响应接口日志记录
 */
function _reslog(res) {
	let _statusCode = res.statusCode;
	if (process.env.NODE_ENV === 'development') {
		console.log("【" + res.config.requestId + "】 地址：" + res.config.url)
		if (res.config.data) {
			console.log("【" + res.config.requestId + "】 请求参数：" + JSON.stringify(res.config.data))
		}
		console.log("【" + res.config.requestId + "】 响应结果：" + JSON.stringify(res))
	}
	//TODO 除了接口服务错误外，其他日志调接口异步写入日志数据库
	switch(_statusCode){
		case 200:
			break;
		case 401:
			break;
		case 404:
			break;
		default:
			break;
	}
}

